﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ADDDF.Infrastructure
{
    /// <summary>
    /// DualKey represents an object which is sutible to be used as the 
    /// key which can uniquely identifies an entity. A DualKey has two values:
    /// instance key, and persistence key. The difference between the two is that
    /// an instance key can be generated quicker (in terms of CPU cycles, network
    /// latencies, and etc) than a persistence key. An entity with a DualKey
    /// gets its instance key when it is created. It gets its persistence key
    /// later in its life cycle, possiblely when it gets added into the repository.
    /// 
    /// Invariants for DualKey include:
    /// - One of the instance key, and the persistence keys must have value (cannot be null).
    /// 
    /// Rule of Keys:
    /// - Both the instance key, and the persistence key must be able to uniquely
    ///     identity an entity without the other. They are not composite keys.
    ///     
    /// How to determine the equality of DualKeys "a", and "b"?
    /// 
    ///           -------------------
    ///           |        a        |
    ///           |-----------------|
    ///           | I   | I+P | P   |
    /// |---------|-----|-----|-----|                                               
    /// |   | I   | I=I | I=I | Err |                    
    /// |   |-----|-----|-----|-----|        
    /// | b | I+P | I=I | P=P | P=P |                    
    /// |   |-----|-----|-----|-----|            
    /// |   | P   | Err | P=P | P=P |                       
    /// -----------------------------                                                
    /// 
    /// (I - has instance key. P - has peristence key. I+P - has both keys)
    /// - I=I: returns equality of both instance keys. 
    /// - P=P: returns equality of both persistence keys.
    /// - Err: throws an exception.
    /// 
    /// In general, perisitence keys has higher priority than instance keys. Compare the
    /// equality of persistence keys when both DualKeys have persistence keys. Otherwise,
    /// compare the equality of instance keys. If one only has the instance key, and 
    /// the other only has the persistence key, the equality comparison throws exception.
    /// 
    /// Stickiness of DualKeys:
    /// 
    /// It is possible that a DualKey, or an entity with a DualKey may be added to
    /// a hash data-structure as a key. Changing the value of a key while it
    /// is in a hash will cause hard-to-troubleshoot errors. To offset this, 
    /// DualKey relies on the convention that a hash-like data-structure calls 
    /// Object.GetHashCode() to obtain the hash code. When this function is called, the
    /// DualKey "sticks" with what was used to generate the hash code, either the 
    /// instance key, or the persistence key. The subsequent calls to Object.GetHashCode()
    /// or Object.Equals() uses this value to perform the given operation. Therefore,
    /// suppose a DualKey x has only instance key, and it has been added into a hash
    /// table. Later x gets its persistence key. However, when comparing equality with
    /// another DualKey y which has only persistence key an exception will be thrown
    /// because x already sticks to its instance key. Now, suppose we get a DualKey
    /// z which has the same persistence key as x but no instance key. Trying to find
    /// x in the hash table using z will not work, and adding z to the hash table will
    /// result in both x and z being in the hash table. These are all the effects of
    /// x being sticked to the instance key.
    /// 
    /// At this point I decide not to use DualKey, give up performance, and simply
    /// always get the permanant key when an entity is created. It is much more manageable.
    /// 
    /// Chen 5/24/2013
    /// 
    /// </summary>
    class DualKey
    {
        // Not to be used.
        private DualKey()
        {
        }
    }
}
